<!-- 通用下拉选择组件 license by http://eleadmin.com -->
<template>
  <el-popover
    ref="popover"
    :value="visible"
    placement="bottom-start"
    :disabled="selectDisabled"
    transition="el-zoom-in-top"
    :popper-class="popperClass"
    :popper-options="popperOptions"
    :width="popperWidth || popperMinWidth"
    @input="updateVisible"
  >
    <div
      slot="reference"
      :class="[
        'el-select ele-fluid',
        selectSize ? 'el-select--' + selectSize : ''
      ]"
    >
      <div
        v-if="multiple"
        ref="tags"
        class="el-select__tags"
        style="max-width: calc(100% - 32px)"
      >
        <span v-if="collapseTags">
          <el-tag
            v-if="firstSel"
            type="info"
            :size="tagSize"
            :closable="!selectDisabled"
            :disable-transitions="true"
            @close="deleteTag($event, firstSel)"
          >
            <span class="el-select__tags-text">{{ firstSel.label }}</span>
          </el-tag>
          <el-tag
            v-if="selected.length > 1"
            type="info"
            :size="tagSize"
            :closable="false"
            :disable-transitions="true"
          >
            <span class="el-select__tags-text">{{ collapseText }}</span>
          </el-tag>
        </span>
        <span v-else>
          <el-tag
            v-for="item in selected"
            :key="item.value"
            type="info"
            :size="tagSize"
            :closable="!selectDisabled"
            :disable-transitions="true"
            @close="deleteTag($event, item)"
          >
            <span class="el-select__tags-text">{{ item.label }}</span>
          </el-tag>
        </span>
      </div>
      <el-input
        ref="input"
        type="text"
        :value="selectedLabel"
        :id="id"
        :name="name"
        :autocomplete="autocomplete"
        :placeholder="currentPlaceholder"
        :size="selectSize"
        :disabled="selectDisabled"
        :readonly="true"
        :validate-event="false"
        :class="{ 'is-focus': visible }"
        @blur="handleBlur"
        @focus="handleFocus"
        @keydown.native.tab="updateVisible(false)"
        @keydown.native.enter.prevent="selectOption"
        @keydown.native.esc.stop.prevent="updateVisible(false)"
        @keydown.native.up.stop.prevent="navigateOptions('prev')"
        @keydown.native.down.stop.prevent="navigateOptions('next')"
        @keydown.native.delete.stop.prevent="handleClearClick"
      >
        <template slot="prefix" v-if="$slots.prefix">
          <slot name="prefix"></slot>
        </template>
        <template slot="suffix">
          <i
            v-if="showClose"
            class="el-select__caret el-input__icon el-icon-circle-close"
            @click.stop="handleClearClick"
          ></i>
          <i :class="iconClass"></i>
        </template>
      </el-input>
    </div>
    <slot></slot>
  </el-popover>
</template>

<script>
  export default {
    name: 'EleBasicSelect',
    inject: {
      elForm: {
        default: ''
      },
      elFormItem: {
        default: ''
      }
    },
    emits: [
      'update:visible',
      'focus',
      'blur',
      'select-option',
      'navigate-options',
      'clear',
      'remove-tag'
    ],
    props: {
      // 绑定值
      value: {
        required: true
      },
      // 是否多选
      multiple: Boolean,
      // 是否禁用
      disabled: Boolean,
      // 尺寸
      size: String,
      // 是否可以清空选项
      clearable: Boolean,
      // 多选时是否将选中值按文字的形式展示
      collapseTags: Boolean,
      // 占位符
      placeholder: String,
      // 对于不可搜索的 Select，是否在输入框获得焦点后自动弹出选项菜单
      automaticDropdown: Boolean,
      // 下拉框的类名
      popperClass: String,
      // popper.js 的参数
      popperOptions: Object,
      // popper宽度
      popperWidth: [Number, String],
      // input 的 id 属性
      id: String,
      // input 的 name 属性
      name: String,
      // input 的 autocomplete 属性
      autocomplete: {
        type: String,
        default: 'off'
      },
      // 单选选中展示的文本
      selectedLabel: {
        type: [String, Number],
        required: true
      },
      // 多选选中的数据
      selected: {
        type: Array,
        required: true
      },
      // popover是否显示
      visible: {
        type: Boolean,
        required: true
      }
    },
    data() {
      return {
        // 输入框初始高度
        initialInputHeight: 0,
        // popper最小宽度
        popperMinWidth: ''
      };
    },
    computed: {
      // 尺寸
      selectSize() {
        const elFormItemSize = this.elFormItem?.elFormItemSize;
        return this.size || elFormItemSize || this.$ELEMENT?.size;
      },
      // 是否禁用
      selectDisabled() {
        return this.disabled || this.elForm?.disabled;
      },
      // 是否已选择
      hasValue() {
        if (this.multiple) {
          return Array.isArray(this.value) && this.value.length > 0;
        } else {
          return (
            typeof this.value !== 'undefined' &&
            this.value !== null &&
            this.value !== ''
          );
        }
      },
      // 箭头图标的class
      iconClass() {
        return [
          'el-select__caret',
          'el-input__icon',
          'el-icon-arrow-up',
          { 'is-reverse': this.visible }
        ];
      },
      // 是否显示清空图标
      showClose() {
        return this.clearable && !this.selectDisabled && this.hasValue;
      },
      // 占位符
      currentPlaceholder() {
        return this.hasValue ? '' : this.placeholder;
      },
      // 多选tag的尺寸
      tagSize() {
        return ['small', 'mini'].includes(this.selectSize) ? 'mini' : 'small';
      },
      // 多选时选中的第一个
      firstSel() {
        return this.selected.length ? this.selected[0] : null;
      },
      // tag折叠显示文字
      collapseText() {
        return '+ ' + (this.selected.length - 1);
      }
    },
    mounted() {
      // 获取input的初始高度
      const input = this.$refs?.input?.$el?.querySelector('input');
      if (input) {
        const sizeMap = {
          mini: 28,
          small: 32,
          medium: 36
        };
        const height = input.getBoundingClientRect().height;
        this.initialInputHeight = height || sizeMap[this.selectSize];
        this.resetInputHeight();
        this.popperMinWidth = input.getBoundingClientRect().width;
      }
    },
    methods: {
      // 修改visible
      updateVisible(value) {
        this.$emit('update:visible', value);
      },
      // 获取焦点
      handleFocus(event) {
        if (this.automaticDropdown && !this.visible) {
          this.updateVisible(true);
        }
        this.$emit('focus', event);
      },
      // 失去焦点
      handleBlur(event) {
        this.$emit('blur', event);
      },
      // 键盘回车选中
      selectOption() {
        if (!this.visible) {
          this.updateVisible(true);
        } else {
          this.$emit('select-option');
        }
      },
      // 键盘上下选择
      navigateOptions(type) {
        if (!this.visible) {
          this.updateVisible(true);
        } else {
          this.$emit('navigate-options', type);
        }
      },
      // 清空
      handleClearClick() {
        this.$emit('clear');
      },
      // 多选删除选中
      deleteTag(event, tag) {
        event.stopPropagation();
        if (!this.selectDisabled) {
          this.$emit('remove-tag', tag);
        }
      },
      // 重置输入框高度
      resetInputHeight() {
        this.$nextTick(() => {
          const childs = this.$refs?.input?.$el?.childNodes ?? [];
          const input = [].find.call(childs, (el) => el.tagName === 'INPUT');
          if (!input) {
            return;
          }
          if (this.collapseTags) {
            input.style.height = null;
            return;
          }
          const tags = this.$refs?.tags;
          const height = Math.round(tags?.getBoundingClientRect()?.height || 0);
          const init = this.initialInputHeight || 40;
          if (!this.selected.length) {
            input.style.height = init + 'px';
          } else {
            const max = Math.max(height + (height > init ? 6 : 0), init);
            input.style.height = max + 'px';
          }
          this.updatePopper();
        });
      },
      // 更新popper位置
      updatePopper() {
        this.$refs?.popover?.updatePopper();
      }
    }
  };
</script>

<style>
  .el-select:not(:hover) > .el-input .el-icon-circle-close {
    display: none;
  }

  .el-select:hover > .el-input .el-icon-circle-close + .el-icon-arrow-up {
    display: none;
  }
</style>
